import { Color, Sprite, Vec3, _decorator, tween, Label, instantiate } from 'cc';
import { EntityManager } from '../../framework/base/EntityManager';
import { IEnemy } from '../../src/shared/common/Interface';
import { EStatus } from '../../src/shared/common/Enum';
import { enemyMachine } from './enemyMachine';
import { CBeHitEffectTime, CEntityShadeColor, DEBUG } from '../../common/Contsant';
import { ObjectPoolManager } from '../../framework/ObjectPoolManager';
import { createUINode } from '../../utils/Util';
import { RenderData } from '../../gameRender/RenderData';
import ResManager, { EPath } from '../../runtime/ResManager';
import { RenderManager } from '../../gameRender/RenderManager';

const { ccclass, property } = _decorator;

@ccclass('enemyEntity')
export class enemyEntity extends EntityManager {
    entityType: number;

    maxHp: number
    curHp: number
    /** 受击时间标记 */
    beHitTimeTag: number
    /** 正在播放死亡动画 */
    playingDieAnim: boolean = false
    /** 死亡标记 */
    isDead: boolean = false
    /** 上一帧坐标 */
    lastPos: [number, number] = [0, 0]
    init(enemy: IEnemy) {
        this.addBody()
        this.setBodyMaterial()
        this.fsm = this.node.addComponent(enemyMachine)
        this.fsm.init(enemy)
        this.state = EStatus.run
    }

    reset(enemy: IEnemy) {
        const { maxHp, curHp, entityType } = enemy
        this.maxHp = maxHp
        this.curHp = curHp
        this.entityType = entityType
        this.isDead = false

        this.node.setScale(3, 3)

        if (DEBUG) {
            // const graphicsNode = this.node.getChildByName('graphicsNode') || createUINode('graphicsNode')
            // graphicsNode.parent = this.node
            // const g = graphicsNode.getComponent(Graphics) || graphicsNode.addComponent(Graphics)
            // g.circle(0, 0, 100)
            // g.lineWidth = 10;
            // g.stroke()

            const labNode = this.node.getChildByName('labNode') || createUINode('labNode')
            labNode.parent = this.node
            const lab = labNode.getComponent(Label) || labNode.addComponent(Label)
            lab.string = '' + enemy.id
        }
    }

    render(enemy: IEnemy) {
        if (this.isDead) return
        const { id, x, y, maxHp, curHp, status, beHit } = enemy

        this.showDmgNumber(enemy)

        this.move(enemy)
        if (status == EStatus.dead) {
            this.dead(id)
            return
        }

        if (beHit.length) {
            this.playBeHitEffect()
        }

        this.state = status
        this.showHpBar(enemy)
        this.showShadow(enemy)
    }

    update(dt: number): void {
        if (this.beHitTimeTag > 0) {
            this.beHitTimeTag -= dt
            if (this.beHitTimeTag <= 0) {
                this.playOriginalEffect()
            }
        }
    }

    /** 移动位置 */
    move(enemy: IEnemy) {
        const { id, x, y, maxHp, curHp, status, beHit } = enemy

        this.node.setPosition(x, y)
        if (status == EStatus.dead) {
            return
        }
        if (x < this.lastPos[0]) {
            this.node.scale_x = -Math.abs(this.node.scale_x)
        } else if (x > this.lastPos[0]) {
            this.node.scale_x = Math.abs(this.node.scale_x)
        }
        this.lastPos = [x, y]
    }

    /** 播放受击特效 */
    playBeHitEffect() {
        if (this.beHitTimeTag > 0) return
        const sprite = this.body.getComponent(Sprite)
        sprite.color = new Color(...CEntityShadeColor.White)
        this.beHitTimeTag = CBeHitEffectTime
    }

    /** 播放原来的效果 */
    playOriginalEffect() {
        const sprite = this.body.getComponent(Sprite)
        sprite.color = new Color(...CEntityShadeColor.Normal)
    }

    /** 死亡 */
    dead(id: number) {
        this.isDead = true
        if (this.playingDieAnim) {
            return
        }
        this.playDeadAni(id)
        this.deleteShowUI(id)
    }

    /** 播放死亡动画 */
    playDeadAni(id: number) {
        this.playingDieAnim = true
        this.node.angle = 0
        tween(this.node)
            .to(0.5, { scale: new Vec3(0, 0), angle: 1440 })
            .call(() => {
                ObjectPoolManager.Ins.poolFree(this)
                RenderData.Ins.enemy2id[id] = null
                this.deadEnd()
            })
            .start()
    }

    /** 死亡动画结束 */
    deadEnd() {
        this.playingDieAnim = false
        this.node.setScale(1, 1)
        this.playOriginalEffect()
    }

    /** 显示阴影 */
    showShadow(enemy: IEnemy) {
        const { x, y, id } = enemy
        if (!RenderData.Ins.shadow2id[id]) {
            RenderData.Ins.shadow2id[id] = ObjectPoolManager.Ins.poolAllocByStr(EPath.shadow)
            if (!RenderData.Ins.shadow2id[id]) {
                RenderData.Ins.shadow2id[id] = instantiate(ResManager.Ins.getPrefabByPath(EPath.shadow))
                RenderData.Ins.shadow2id[id].parent = RenderManager.Ins.shadowArea
            }
            RenderData.Ins.shadow2id[id].active = true
            RenderData.Ins.shadow2id[id].uiSprite.color = new Color(85, 85, 85, 170)
        }
        RenderData.Ins.shadow2id[id].setPosition(x, y - 30)
    }

    /** 显示生命条 */
    showHpBar(enemy: IEnemy) {
        const { x, y, id, curHp, maxHp } = enemy
        if (!RenderData.Ins.hpBar2id[id]) {
            RenderData.Ins.hpBar2id[id] = ObjectPoolManager.Ins.poolAllocByStr(EPath.hpbar)
            if (!RenderData.Ins.hpBar2id[id]) {
                RenderData.Ins.hpBar2id[id] = instantiate(ResManager.Ins.getPrefabByPath(EPath.hpbar))
                RenderData.Ins.hpBar2id[id].parent = RenderManager.Ins.barArea
            }
            RenderData.Ins.hpBar2id[id].active = true
        }
        RenderData.Ins.hpBar2id[id].setPosition(x, y + 40)
        RenderData.Ins.hpBar2id[id].getChildByName('bar').uiTransform.width = 49 * curHp / maxHp
    }

    deleteShowUI(id: number) {
        ObjectPoolManager.Ins.poolFreeByStr(EPath.shadow, RenderData.Ins.shadow2id[id])
        ObjectPoolManager.Ins.poolFreeByStr(EPath.hpbar, RenderData.Ins.hpBar2id[id])

        RenderData.Ins.shadow2id[id] = null
        RenderData.Ins.hpBar2id[id] = null
    }

    /** 伤害飘字 */
    showDmgNumber(enemy: IEnemy) {
        const { x, y, beHit } = enemy
        if (beHit.length) {
            for (const { dmg, isCri } of beHit) {
                RenderManager.Ins.showDmgNumber(dmg, x, y, isCri)
            }
        }
    }
}